/*******************************************************************************
 * Copyright (c) 2010 liw.
 * All rights reserved. 
 * 
 * This file is part of VanBus.
 * 
 *     VanBus is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     VanBus is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with VanBus.  If not, see <http://www.gnu.org/licenses/>.
 * Contributors:
 *     liw - initial API and implementation
 ******************************************************************************/
package org.niclab.vanbus.activity;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.apache.http.client.ResponseHandler;
import org.niclab.vanbus.R;
import org.niclab.vanbus.activity.comp.EndStopReminderDialog;
import org.niclab.vanbus.activity.comp.MenuDialog;
import org.niclab.vanbus.activity.comp.StartStopReminderDialog;
import org.niclab.vanbus.activity.controller.BusRouteController;
import org.niclab.vanbus.activity.controller.BusStopController;
import org.niclab.vanbus.application.VanBusApplication;
import org.niclab.vanbus.database.ApplicationDataBase;
import org.niclab.vanbus.database.BusRouteDAO;
import org.niclab.vanbus.database.BusStopDAO;
import org.niclab.vanbus.database.ReminderDAO;
import org.niclab.vanbus.gps.MyLocationManager;
import org.niclab.vanbus.model.BusRoute;
import org.niclab.vanbus.model.BusStop;
import org.niclab.vanbus.model.EndStopReminder;
import org.niclab.vanbus.model.StartStopReminder;
import org.niclab.vanbus.model.Reminder.ReminderType;
import org.niclab.vanbus.model.viewadpater.BusStopArrayAdapter;
import org.niclab.vanbus.model.viewadpater.CommonListAdapter;
import org.niclab.vanbus.preference.AppPreferences;
import org.niclab.vanbus.query.BusStopCoordinatesQuery;
import org.niclab.vanbus.query.ClosestBusStopsQuery;
import org.niclab.vanbus.query.IQuery;
import org.niclab.vanbus.query.RouteStopsWithTimesQuery;
import org.niclab.vanbus.query.RoutesAtStopQuery;
import org.niclab.vanbus.query.SimpleQueryWorker;
import org.niclab.vanbus.query.WalkingDirectionQuery;
import org.niclab.vanbus.query.command.ClosestStopsByRouteUICmd;
import org.niclab.vanbus.query.command.DismissDialogCmd;
import org.niclab.vanbus.query.command.ICommand;
import org.niclab.vanbus.query.command.ICommandChain;
import org.niclab.vanbus.query.command.ShowDialogCmd;
import org.niclab.vanbus.query.command.ToggleBusyLoadingPanelCmd;
import org.niclab.vanbus.query.command.UpdateListViewCmd;
import org.niclab.vanbus.query.handler.IQueryHandler;
import org.niclab.vanbus.query.mem.SimpleMemQueryHandler;
import org.niclab.vanbus.query.ws.ClosestBusStopsWSQueryResResolver;
import org.niclab.vanbus.query.ws.GoogleDirectionWSQueryResResolver;
import org.niclab.vanbus.query.ws.RouteStopsWithTimesWSQueryResResolver;
import org.niclab.vanbus.query.ws.RouteWSQueryResResolver;
import org.niclab.vanbus.query.ws.SimpleWSQueryHandler;
import org.niclab.vanbus.query.ws.StopCoordsWSQueryResResolver;
import org.niclab.vanbus.query.ws.StopTimesWSQueryResResolver;
import org.niclab.vanbus.query.ws.StopCoordsWSQueryResResolver.QueryResult;
import org.niclab.vanbus.utils.CacheUtils;
import org.niclab.vanbus.utils.Converter;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.preference.PreferenceManager;
import android.test.IsolatedContext;
import android.text.Layout;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Animation.AnimationListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TimePicker.OnTimeChangedListener;

public class StopListOfRouteAct extends ListActivity {

	private static final String LOG_TAG = "RouteStopListAct";

	private final static int DIALOG_GENERAL_BUSY = 1;
	private final static int DIALOG_GENERAL_ALERT = 2;
	private final static int DIALOG_START_STOP_REMINDER = 3;
	private final static int DIALOG_END_STOP_REMINDER = 4;
	private final static int DIALOG_ROUTE_MENU = 5;
	private final static int DIALOG_STOP_MENU = 6;

	private BusRoute busRoute;

	private BusRouteController busRouteController;
	private BusStopController busStopController;

	private RouteMenuDialog routeMenu;
	private StopMenuDialog stopMenu;

	private CommonListAdapter model;

	private String dialogBusyMsg;
	private String dialogAlertMsg;

	private StartStopReminderDialog startStopReminderDialog;
	private EndStopReminderDialog endStopReminderDialog;

	private int selectedRowPosition;
	private View selectedRowView;

	public enum StopMenuItem {
		Show_On_Map("Show on map"), Start_Stop_Reminder(
				"Set start stop reminder"), End_Stop_Reminder(
				"Set destination stop reminder"), Update_Time_Schedule(
				"Update time schedule"), Add_Favorite("Add favorite"), Remove_Favorite(
				"Remove favorite");

		private String str;

		StopMenuItem(String str) {
			this.str = str;
		}

		public String toString() {
			return this.str;
		}

	}

	public enum RouteMenuItem {
		Closest_Stop("Closest Stop"), Update_Schedule("Update Schedule"), Add_Favorite(
				"Add Favorite"), Remove_Favorite("Remove Favorite");

		private String str;

		RouteMenuItem(String str) {
			this.str = str;
		}

		public String toString() {
			return this.str;
		}

	}

	private class RouteMenuDialog extends MenuDialog<RouteMenuItem> {

		
		public RouteMenuDialog(Activity ownerActivity) {
			super(ownerActivity, android.R.layout.select_dialog_item,
					RouteMenuItem.class);

		}

		@Override
		public void decorateMenu(AlertDialog dialog) {
			dialog.setTitle(busRoute.getRouteId() + " "
					+ busRoute.getRouteDir() + " " + busRoute.getRouteName());

		}

		@Override
		public void onItemSelected(RouteMenuItem selected) {

			switch (selected) {
			case Closest_Stop:
				findClosestStop();
				break;
			case Update_Schedule:
				updateRouteSchedule();
				break;
			case Add_Favorite:
				addFavoriteRoute();
				break;
			case Remove_Favorite:
				cancelFavoriteRoute();
				break;

			}

		}

		public void prepareMenuDialog(Dialog dialog) {
			EnumSet<RouteMenuItem> set = EnumSet.allOf(RouteMenuItem.class);
			if (!busRoute.isFavorite()) {
				set.remove(RouteMenuItem.Remove_Favorite);

			} else {
				set.remove(RouteMenuItem.Add_Favorite);

			}

			super.prepareMenuDialog(dialog, set);

		}

	}

	private class StopMenuDialog extends MenuDialog<StopMenuItem> {

		BusStop stop;
		

		public StopMenuDialog(Activity ownerActivity) {
			super(ownerActivity, android.R.layout.select_dialog_item,
					StopMenuItem.class);

		}

		public void setBusStop(BusStop stop) {
			this.stop = stop;
		}

		@Override
		public void decorateMenu(AlertDialog dialog) {
			dialog.setTitle(stop.getStopId() + " " + stop.getStopName());
		}

		@Override
		public void onItemSelected(StopMenuItem selected) {

			switch (selected) {
			case Show_On_Map:
				viewOnMap(stop);
				break;
			case Start_Stop_Reminder:
				setStartStopReminder(stop);
				break;
			case End_Stop_Reminder:
				setEndStopReminder(stop);
				break;
			case Update_Time_Schedule:
				updateStopSchedule(stop);
				break;
			case Add_Favorite:
				addFavoriteStop(stop);
				break;
			case Remove_Favorite:
				cancelFavoriteStop(stop);
				break;
			}
		}

		public void prepareMenuDialog(Dialog dialog) {
			
			EnumSet<StopMenuItem> set = EnumSet.allOf(StopMenuItem.class);			
			if (stop.isFavorite()) {
				
				set.remove(StopMenuItem.Add_Favorite);
			} else {
				
				set.remove(StopMenuItem.Remove_Favorite);
			}
			super.prepareMenuDialog(dialog, set);

		}

	}

	@Override
	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
		this.setContentView(R.layout.bus_stop_list);

		// get the currently selected bus route
		Intent intent = getIntent();
		String routeKey = intent
				.getStringExtra(getString(R.string.currently_selected_bus_route));
		busRoute = (BusRoute) ((VanBusApplication) this.getApplication())
				.getAndRemoveTempData(routeKey);

		String initStopId = intent
				.getStringExtra(getString(R.string.currently_selected_bus_stop));

		busRouteController = new BusRouteController(busRoute);
		busStopController = new BusStopController();
		initializeTitle();

		// BusStopArrayAdapter stopAdapter = new
		// BusStopArrayAdapter(this,R.layout.bus_stop_row,busRoute);
		model = new CommonListAdapter(this, R.layout.bus_stop_row);
		this.setListAdapter(model);

		startRetrieveStops(initStopId);

		// menus
		routeMenu = new RouteMenuDialog(this);
		stopMenu = new StopMenuDialog(this);
		// register stop menu
		final Activity that = this;
		ListView listView = getListView();
		listView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				// activity.openContextMenu(view);
				setSelectedRow(view, position);
				BusStop stop = getBusStopFromList(position);
				stopMenu.setBusStop(stop);
				busStopController.setBusStop(stop);
				that.showDialog(DIALOG_STOP_MENU);
			}
		});

		dialogBusyMsg = getString(R.string.dialog_loading_busy_msg);

	}

	private void setSelectedRow(View view, int position) {
		this.selectedRowView = view;
		this.selectedRowPosition = position;

	}

	private int getSelectedRowPosition() {
		return this.selectedRowPosition;

	}

	private View getSelectedRowView() {
		return this.selectedRowView;
	}

	// TODO cursor not handled at this point.
	private BusStop getBusStopFromList(int position) {
		if(position<0 || position >= model.getCount())
			return null;
		Object obj = getListAdapter().getItem(position);

		if (obj instanceof BusStop) {
			return (BusStop) obj;

		} else if (obj instanceof Cursor) {
			return null;
		}

		return null;

	}

	private void initializeTitle() {

		getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
				R.layout.bus_stop_list_title_bar);
		TextView busNo = (TextView) findViewById(R.id.stop_list_title_bar_route_no);
		busNo.setText(busRoute.getRouteId());

		TextView busDir = (TextView) findViewById(R.id.stop_list_title_bar_route_dir);
		busDir.setText(busRoute.getRouteDir());

		TextView busName = (TextView) findViewById(R.id.stop_list_title_bar_route_name);
		String name = busRoute.getRouteName();
		busName.setText(name.substring(name.indexOf('-') + 1));

		toggleFavoriteRouteIcon();

		// register route menu
		View titleBar = findViewById(R.id.stop_list_title_bar);
		final Activity parentAct = this;
		titleBar.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				parentAct.showDialog(DIALOG_ROUTE_MENU);

			}
		});

	}

	private void toggleFavoriteRouteIcon() {

		ImageView fav = (ImageView) findViewById(R.id.stop_list_title_bar_fav);
		if (busRoute.isFavorite())
			fav.setImageResource(android.R.drawable.star_on);
		else
			fav.setImageResource(android.R.drawable.star_off);
	}

	private void setBusyMessage(String msg) {
		this.dialogBusyMsg = msg;

	}

	private void setAlertMessage(String msg) {
		this.dialogAlertMsg = msg;
	}

	private void startRetrieveStops(final String initStopId) {

		final SimpleQueryWorker worker = busRouteController.loadBusStops();

		// Sync commands
		// populate models
		ICommand popModelCmd = new ICommand() {

			@Override
			public void execute(Object input, ICommandChain chain) {

				BusStopArrayAdapter adapter = new BusStopArrayAdapter(model
						.getContext(), model.getResourceId(), busRoute);
				model.setBaseAdapter(adapter);

				chain.execute(input);
			}

		};

		worker.addWorkerPostCommand(popModelCmd);

		// Async Commands

		// PreCommand
		ICommand displayBusyPanel = new ToggleBusyLoadingPanelCmd(this);

		worker.addAsyncPreCommand(displayBusyPanel);

		// PostCommand

		ICommand dismissBusyPanel = new ToggleBusyLoadingPanelCmd(this);
		ICommand updateViewAsync = new UpdateListViewCmd(this);

		ICommand scrollToStopCmd = new ICommand() {

			@Override
			public void execute(Object input, ICommandChain chain) {
				if (initStopId != null) {
					List<BusStop> stops = busRoute.getStops();
					int position = -1;
					for (int i = 0; i < stops.size(); i++) {
						if (stops.get(i).getStopId().equalsIgnoreCase(
								initStopId)) {
							position = i;
							break;
						}
					}
					if (position > -1) {
						getListView().setSelection(position);
						
					}
				}

				chain.execute(input);
			}

		};
		//worker.addAsyncPostCommand(popModelCmd);
		worker.addAsyncPostCommand(dismissBusyPanel);
		worker.addAsyncPostCommand(updateViewAsync);
		worker.addAsyncPostCommand(scrollToStopCmd);

		// ProgressCommand
		worker.addAsyncProgressCommand(updateViewAsync);

		worker.work();

	}

	@Override
	protected void onPrepareDialog(final int id, final Dialog dialog) {
		switch (id) {
		case DIALOG_GENERAL_BUSY:
			ProgressDialog pDialog = (ProgressDialog) dialog;
			pDialog.setMessage(dialogBusyMsg);
			break;
		case DIALOG_GENERAL_ALERT:
			Log.d(LOG_TAG, "prepare a general alert dialog");
			AlertDialog aDialog = (AlertDialog) dialog;
			aDialog.setMessage(dialogAlertMsg);
			break;
		case DIALOG_START_STOP_REMINDER:
			startStopReminderDialog.prepareDialog(dialog);
			break;
		case DIALOG_END_STOP_REMINDER:
			endStopReminderDialog.prepareDialog(dialog);
			break;
		case DIALOG_ROUTE_MENU:
			((RouteMenuDialog) routeMenu).prepareMenuDialog(dialog);
			break;
		case DIALOG_STOP_MENU:
			((StopMenuDialog) stopMenu).prepareMenuDialog(dialog);
			break;

		}

	}

	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dialog;
		switch (id) {

		case DIALOG_GENERAL_BUSY:
			ProgressDialog pDialog = new ProgressDialog(this);
			pDialog.setMessage(getString(R.string.dialog_loading_busy_msg));
			pDialog.setIndeterminate(true);
			dialog = pDialog;
			break;

		case DIALOG_GENERAL_ALERT:
			Log.d(LOG_TAG, "creat a general alert dialog");
			AlertDialog.Builder aDialog = new AlertDialog.Builder(this);
			aDialog.setMessage(dialogAlertMsg);
			aDialog.setPositiveButton("Yes",
					new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();

						}
					});
			dialog = aDialog.create();
			break;
		case DIALOG_START_STOP_REMINDER:

			dialog = startStopReminderDialog.createDialog();
			break;

		case DIALOG_END_STOP_REMINDER:
			dialog = endStopReminderDialog.createDialog();
			break;

		case DIALOG_ROUTE_MENU:
			dialog = routeMenu.createMenuDialog();
			break;

		case DIALOG_STOP_MENU:
			dialog = stopMenu.createMenuDialog();
			break;
		default:
			dialog = null;
		}

		return dialog;

	}

	private void toggleFavoriteStopIcon(View rowView, BusStop stop) {

		ImageView fav = (ImageView) rowView.findViewById(R.id.bus_stop_fav);
		if (stop.isFavorite())
			fav.setImageResource(android.R.drawable.star_big_on);
		else
			fav.setImageResource(android.R.drawable.star_big_off);

	}

	private void addFavoriteStop(BusStop stop) {
		busStopController.setBusStop(stop);
		busStopController.addFavoriteStop(this.getApplicationContext());
		toggleFavoriteStopIcon(getSelectedRowView(), stop);
		this.sendBroadcast(new Intent(this
				.getString(R.string.favorites_tab_stop_update)));

	}

	private void cancelFavoriteStop(BusStop stop) {
		busStopController.setBusStop(stop);
		busStopController.cancelFavoriteStop(this.getApplicationContext());
		toggleFavoriteStopIcon(getSelectedRowView(), stop);
		this.sendBroadcast(new Intent(this
				.getString(R.string.favorites_tab_stop_update)));

	}

	// update a stop schedule
	private void updateStopSchedule(final BusStop stop) {
		busStopController.setBusStop(stop);
		SimpleQueryWorker worker = busStopController
				.updateStopSchedule(busRoute);

		// post command

		final Context context = this;
		ICommand refreshRowCommand = new ICommand() {

			@Override
			public void execute(Object input, ICommandChain chain) {
				stop.setRefreshed(true);
				getListAdapter().getView(getSelectedRowPosition(),
						getSelectedRowView(), getListView());
				stop.setRefreshed(false);
			}

		};

		worker.addAsyncPostCommand(refreshRowCommand);
		worker.work();

	}

	// set a start stop reminder
	private void setStartStopReminder(final BusStop stop) {
		// show reminder dialog
		if (startStopReminderDialog == null)
			startStopReminderDialog = new StartStopReminderDialog(this);

		StartStopReminder reminder = new StartStopReminder(busRoute, stop);
		startStopReminderDialog.setReminder(reminder);
		String title = busRoute.getRouteId() + " "	+ busRoute.getRouteDir() + " " + stop.getStopName();
		Log.d(LOG_TAG, "dialog title" + title);
		startStopReminderDialog.setTitle(title);
		startStopReminderDialog.setFutureTimes(stop.getTimesString(busRoute));
		startStopReminderDialog.setDate(Calendar.getInstance());
		
		
		// get current Location
		//Location loc = LocationUtils.getIntance(this.getApplicationContext()).getCurrentLocation(false);
		MyLocationManager locMan = VanBusApplication.getInstance().getMyLocationManager();
		if (!locMan.isGPSEnabled() ||locMan.getCurrentBestLocation(0)==null) {
			Log.d(LOG_TAG, "current location is empty");
			startStopReminderDialog.setWalkingDistanceMessage("N/A(No GPS available)");
			startStopReminderDialog.setWalkingTimeMessage("N/A(No GPS available)");
			showDialog(DIALOG_START_STOP_REMINDER);
			return;
		}

		busStopController.setBusStop(stop);
		final SimpleQueryWorker worker = busStopController.queryWalkingDirectionToStop(null);

		// connect the pre and post commands
		this.setBusyMessage("Calculating walking distance and estimated time, Please wait ...");
		ShowDialogCmd busyDialog = new ShowDialogCmd(this, this.DIALOG_GENERAL_BUSY);

		worker.addAsyncPreCommand(busyDialog);

		// dismiss the busy dialog
		DismissDialogCmd dimissBusyDialog = new DismissDialogCmd(this,this.DIALOG_GENERAL_BUSY);
		worker.addAsyncPostCommand(dimissBusyDialog);

		

		ICommand showReminderDialog = new ICommand() {

			@Override
			public void execute(Object input, ICommandChain chain) {
				

				Log.d(LOG_TAG,"setStartStopReminder: "+ worker.getLastFinishedQuery().getClass());
				Log.d(LOG_TAG,"setStartStopReminder: "+worker.getLastFinishedQuery().getQueryResult().getClass());
				
				GoogleDirectionWSQueryResResolver.QueryResult qResult = (org.niclab.vanbus.query.ws.GoogleDirectionWSQueryResResolver.QueryResult) worker.getLastFinishedQuery().getQueryResult();

				String distance = Converter.convertDistancetoString(qResult
						.getDistance());
				String duration = Converter.convertDurationtoString(qResult
						.getDuration());
			
				startStopReminderDialog.setWalkingDistanceMessage(distance);
				startStopReminderDialog.setWalkingTimeMessage(duration);

				StopListOfRouteAct.this.showDialog(DIALOG_START_STOP_REMINDER);
				chain.execute(input);

			}

		};

		worker.addAsyncPostCommand(showReminderDialog);

		worker.work();

	}

	private void setEndStopReminder(final BusStop stop) {

		int selectedPos = getSelectedRowPosition();
		final BusStop prevStop = getBusStopFromList(selectedPos - 1);
		final BusStop nextStop = getBusStopFromList(selectedPos + 1);

		SimpleQueryWorker worker = busStopController.queryStopGeoLoc(stop);

		if (prevStop != null) {
			worker.connectWorker(busStopController.queryStopGeoLoc(prevStop));
		} else {
			this.setAlertMessage("Sorry, can not set an end reminder for a start stop!");
			this.showDialog(StopListOfRouteAct.DIALOG_GENERAL_ALERT);
			return;

		}

		if (nextStop != null) {
			worker.connectWorker(busStopController.queryStopGeoLoc(nextStop));
		}

		

		// connect the pre and post commands
		this.setBusyMessage("Retrieving destination stop's coordinates. Please wait...");
		ShowDialogCmd busyDialog = new ShowDialogCmd(this,
				this.DIALOG_GENERAL_BUSY);

		worker.addAsyncPreCommand(busyDialog);

		// post command: dismiss the busy dialog
		DismissDialogCmd dimissBusyDialog = new DismissDialogCmd(this,
				this.DIALOG_GENERAL_BUSY);
		worker.addAsyncPostCommand(dimissBusyDialog);

		if (endStopReminderDialog == null) {
			endStopReminderDialog = new EndStopReminderDialog(
					StopListOfRouteAct.this);
		}
		EndStopReminder reminder = new EndStopReminder(busRoute, prevStop,
				stop, nextStop);
		endStopReminderDialog.setReminder(reminder);

		// post command: show the reminder dialog
		ICommand showReminderDialog = new ICommand() {

			@Override
			public void execute(Object input, ICommandChain chain) {

				endStopReminderDialog.setTitle(busRoute.getRouteId() + " "
						+ busRoute.getRouteDir() + " " + stop.getStopName());
											
				showDialog(DIALOG_END_STOP_REMINDER);

			}

		};

		worker.addAsyncPostCommand(showReminderDialog);

		worker.work();

	}

	// view this stop on Map
	private void viewOnMap(final BusStop stop) {
	
		//get the stop's gps coordinates
		busStopController.setBusStop(stop);
		final SimpleQueryWorker worker = busStopController.queryStopGeoLoc(stop);

		// connect the pre and post commands
		this.setBusyMessage("Retrieving stop's location, Please wait ...");
		ShowDialogCmd busyDialog = new ShowDialogCmd(this, this.DIALOG_GENERAL_BUSY);

		worker.addAsyncPreCommand(busyDialog);

		// dismiss the busy dialog
		DismissDialogCmd dimissBusyDialog = new DismissDialogCmd(this,this.DIALOG_GENERAL_BUSY);
		worker.addAsyncPostCommand(dimissBusyDialog);

		final Context context =this;
		ICommand showMapView = new ICommand() {

			@Override
			public void execute(Object input, ICommandChain chain) {
								
				Intent startMap = new Intent().setClass(context, OverlayMapAct.class);
				String key = stop.getStopId();
				
				VanBusApplication.getInstance().saveTempData(key, stop);
				startMap.putExtra(context.getString(R.string.currently_selected_bus_stop), key);
				context.startActivity(startMap);
				chain.execute(input);

			}

		};

		worker.addWorkerPostCommand(showMapView);

		//worker.addSyncPostCmd(showMapView);
		worker.work();
		
		

	}

	// set current route to favorite
	private void addFavoriteRoute() {

		busRouteController.addFavoriteRoute(this.getApplicationContext());
		toggleFavoriteRouteIcon();
		

	}

	private void cancelFavoriteRoute() {

		busRouteController.cancelFavoriteRoute(this.getApplicationContext());
		toggleFavoriteRouteIcon();

	}

	// force to update the route's schedule
	private void updateRouteSchedule() {

		SimpleQueryWorker worker = busRouteController.updateRouteSchedule();

		// PreCommand
		ICommand displayBusyPanel = new ToggleBusyLoadingPanelCmd(
				StopListOfRouteAct.this);

		worker.addAsyncPreCommand(displayBusyPanel);

		// PostCommand
		ICommand dismissBusyPanel = new ToggleBusyLoadingPanelCmd(
				StopListOfRouteAct.this);
		ICommand updateViewAsync = new UpdateListViewCmd(
				StopListOfRouteAct.this);

		// populate models
		ICommand popModelCmd = new ICommand() {

			@Override
			public void execute(Object input, ICommandChain chain) {

				BusStopArrayAdapter adapter = new BusStopArrayAdapter(model
						.getContext(), model.getResourceId(), busRoute);
				model.setBaseAdapter(adapter);

				chain.execute(input);
			}

		};

		worker.addAsyncPostCommand(popModelCmd);
		worker.addAsyncPostCommand(dismissBusyPanel);
		worker.addAsyncPostCommand(updateViewAsync);

		// ProgressCommand
		worker.addAsyncProgressCommand(updateViewAsync);

		worker.work();

	}

	// find the closest stop
	private void findClosestStop() {

		// get current Location
		//Location loc = LocationUtils.getIntance(this.getApplicationContext()).getCurrentLocation(true);
		MyLocationManager locMan = VanBusApplication.getInstance().getMyLocationManager();
		if (!locMan.isGPSorNetworkEnabled()||locMan.getCurrentBestLocation(0)==null) {
			setAlertMessage(getString(R.string.no_location_available_dialog_message));
			this.showDialog(DIALOG_GENERAL_ALERT);
			return;
		}

		/*double curLat = loc.getLatitude();
		double curLng = loc.getLongitude();*/

		final SimpleQueryWorker worker = busRouteController.findClosestStop(
				0.0, 0.0);

		// IPreCommand
		// display a loading panel
		ICommand displayBusyPanel = new ToggleBusyLoadingPanelCmd(this);
		worker.addAsyncPreCommand(displayBusyPanel);

		// PostCommand
		// post command: refine the query result
		ICommand refineResultCmd = new ICommand() {

			@Override
			public void execute(Object input, ICommandChain chain) {
				ClosestBusStopsWSQueryResResolver.QueryResult result = (org.niclab.vanbus.query.ws.ClosestBusStopsWSQueryResResolver.QueryResult) worker
						.getLastFinishedQuery().getQueryResult();
				List<BusStop> stops = result.getStops();
				List<Integer> itemPositions = new ArrayList<Integer>();

				// List<BusStop> curStops = route.getStops();
				HashSet<BusStop> set = new HashSet<BusStop>(stops);

				for (int i = 0; i < model.getCount(); i++) {
					BusStop stop = getBusStopFromList(i);
					stop.setClosest(false); // clear the value set before
					if (set.contains(stop)) {
						stop.setClosest(true);
						itemPositions.add(i);
					}

				}

				chain.execute(itemPositions);
			}

		};

		// dismiss the loading panel
		ICommand dismissBusyPanel = new ToggleBusyLoadingPanelCmd(this);
		// updateUI
		ICommand updateUI = new ClosestStopsByRouteUICmd(this.getListView(), model);

		worker.addAsyncPostCommand(refineResultCmd);
		worker.addAsyncPostCommand(dismissBusyPanel);
		worker.addAsyncPostCommand(updateUI);
		worker.work();

	}

}
